#include "transmit_manager.h"
#include "config_boot.h"
#include "config_data.h"
#include "config_factory.h"
#include "factory_api.h"
#include "gateway_manager.h"
#include "gb_15322_pal.h"
#include "interaction_manager.h"
#include "manager_queue.h"
#include "manager_queue_comm.h"
#include "module_queue_struct.h"
#include "net_app.h"
#include "net_prot.h"
#include "serial_app.h"
#include "transparent_protocol.h"
#include "uc_log.h"
#include "wiota_flashing.h"
#include <rtdevice.h>
#include <rtthread.h>

typedef struct
{
    unsigned int dev_id;
    char fmt[8];
    int ob; // order business 顺序业务，0 或 1
    unsigned char data[0];
} transmit_user_data_t;

typedef struct
{
    unsigned int src_addr;
    unsigned int dest_addr;
    char fmt[8];
    unsigned char data[0];
} transmit_transparent_data_t;

typedef struct
{
    unsigned int dev_id;
    unsigned char data[0];
} transmit_iote_state_t;

typedef struct
{
    unsigned int dev_id;
    unsigned int status;
} transmit_device_status_t;

static unsigned int transmit_cmd_to_wiota_cmd(unsigned int trans_cmd)
{
    unsigned int cmd = -1;

    switch (trans_cmd)
    {
    case TRANSMIT_WIOAT_VERSION_GET:
        cmd = WIOAT_VERSION_GET;
        break;

    case TRANSMIT_WIOTA_SYS_CFG_GET:
        cmd = WIOTA_SYS_CFG_GET;
        break;
    case TRANSMIT_WIOTA_SYS_CFG_SET:
        cmd = WIOTA_SYS_CFG_SET;
        break;

    case TRANSMIT_WIOTA_ACT_CFG_GET:
        cmd = WIOTA_ACT_CFG_GET;
        break;
    case TRANSMIT_WIOTA_ACT_CFG_SET:
        cmd = WIOTA_ACT_CFG_SET;
        break;

    case TRANSMIT_WIOTA_FREQ_CFG_GET:
        cmd = WIOTA_FREQ_CFG_GET;
        break;
    case TRANSMIT_WIOTA_FREQ_CFG_SET:
        cmd = WIOTA_FREQ_CFG_SET;
        break;

    case TRANSMIT_WIOTA_POWER_CFG_GET:
        cmd = WIOTA_POWER_CFG_GET;
        break;
    case TRANSMIT_WIOTA_POWER_CFG_SET:
        cmd = WIOTA_POWER_CFG_SET;
        break;

    case TRANSMIT_WIOTA_RATE_CFG_GET:
        cmd = WIOTA_RATE_CFG_GET;
        break;
    case TRANSMIT_WIOTA_RATE_CFG_SET:
        cmd = WIOTA_RATE_CFG_SET;
        break;

    case TRANSMIT_WIOTA_PAGING_TX_CFG_GET:
        cmd = WIOTA_PAGING_TX_CFG_GET;
        break;
    case TRANSMIT_WIOTA_PAGING_TX_CFG_SET:
        cmd = WIOTA_PAGING_TX_CFG_SET;
        break;

    case TRANSMIT_WIOTA_SYNC_PAGING_CFG_GET:
        cmd = WIOTA_SYNC_PAGING_CFG_GET;
        break;
    case TRANSMIT_WIOTA_SYNC_PAGING_CFG_SET:
        cmd = WIOTA_SYNC_PAGING_CFG_SET;
        break;

    case TRANSMIT_WIOTA_TS_CFG_GET:
        cmd = WIOTA_TS_CFG_GET;
        break;
    case TRANSMIT_WIOTA_TS_CFG_SET:
        cmd = WIOTA_TS_CFG_SET;
        break;
#ifdef WIOTA_SUBF_MODE_SUPPORT
    case TRANSMIT_WIOTA_SUBF_MODE_CFG_GET:
        cmd = WIOTA_SUBF_MODE_CFG_GET;
        break;
    case TRANSMIT_WIOTA_SUBF_MODE_CFG_SET:
        cmd = WIOTA_SUBF_MODE_CFG_SET;
        break;
#endif
    case TRANSMIT_SLOT_SEND_CFG_GET:
        cmd = SLOT_SEND_CFG_GET;
        break;
    case TRANSMIT_SLOT_SEND_CFG_SET:
        cmd = SLOT_SEND_CFG_SET;
        break;

    case TRANSMIT_GATEWAY_BASE_CFG_GET:
        cmd = GATEWAY_BASE_CFG_GET;
        break;
    case TRANSMIT_GATEWAY_BASE_CFG_SET:
        cmd = GATEWAY_BASE_CFG_SET;
        break;

    case TRANSMIT_ID_MANAGER_CFG_GET:
        cmd = ID_MANAGER_CFG_GET;
        break;
    case TRANSMIT_ID_MANAGER_CFG_SET:
        cmd = ID_MANAGER_CFG_SET;
        break;

    case TRANSMIT_AUTH_CFG_GET:
        cmd = AUTH_CFG_GET;
        break;
    case TRANSMIT_AUTH_CFG_SET:
        cmd = AUTH_CFG_SET;
        break;

    case TRANSMIT_NET_POLICY_CFG_GET:
        cmd = NET_POLICY_CFG_GET;
        break;
    case TRANSMIT_NET_POLICY_CFG_SET:
        cmd = NET_POLICY_CFG_SET;
        break;

    case TRANSMIT_NET_IF_CFG_GET:
        cmd = NET_IF_CFG_GET;
        break;
    case TRANSMIT_NET_IF_CFG_SET:
        cmd = NET_IF_CFG_SET;
        break;

    case TRANSMIT_WIFI_CFG_GET:
        cmd = WIFI_CFG_GET;
        break;
    case TRANSMIT_WIFI_CFG_SET:
        cmd = WIFI_CFG_SET;
        break;

    case TRANSMIT_CAT1_CFG_GET:
        cmd = CAT1_CFG_GET;
        break;
    case TRANSMIT_CAT1_CFG_SET:
        cmd = CAT1_CFG_SET;
        break;

    case TRANSMIT_BT_CFG_GET:
        cmd = BT_CFG_GET;
        break;

    case TRANSMIT_MQTT_SERVER_CFG_GET:
        cmd = MQTT_SERVER_CFG_GET;
        break;
    case TRANSMIT_MQTT_SERVER_CFG_SET:
        cmd = MQTT_SERVER_CFG_SET;
        break;

    case TRANSMIT_DATA_CFG_GET:
        cmd = DATA_CFG_GET;
        break;
    case TRANSMIT_DATA_CFG_SET:
        cmd = DATA_CFG_SET;
        break;

    case TRANSMIT_WATCHDOG_CFG_GET:
        cmd = WATCHDOG_CFG_GET;
        break;
    case TRANSMIT_WATCHDOG_CFG_SET:
        cmd = WATCHDOG_CFG_SET;
        break;

    case TRANSMIT_FTP_LOG_CFG_GET:
        cmd = GATEWAY_FTP_LOG_CFG_GET;
        break;
    case TRANSMIT_FTP_LOG_CFG_SET:
        cmd = GATEWAY_FTP_LOG_CFG_SET;
        break;

    case TRANSMIT_LOG_SWITCH_CFG_GET:
        cmd = LOG_SWITCH_CFG_GET;
        break;
    case TRANSMIT_LOG_SWITCH_CFG_SET:
        cmd = LOG_SWITCH_CFG_SET;
        break;

    case TRANSMIT_UART_485_CFG_GET:
        cmd = UART_485_CFG_GET;
        break;
    case TRANSMIT_UART_485_CFG_SET:
        cmd = UART_485_CFG_SET;
        break;

    case TRANSMIT_STATIC_DATA_INIT:
        cmd = RESET_FACTORY;
        break;

    case TRANSMIT_GATEWAY_REBOOT:
        cmd = GATEWAY_REBOOT;
        break;

    case TRANSMIT_UBOOT_CFG_GET:
        cmd = UBOOT_CFG_GET;
        break;
    case TRANSMIT_UBOOT_CFG_SET:
        cmd = UBOOT_CFG_SET;
        break;

    case TRANSMIT_TIMED_CFG_GET:
        cmd = GATEWAY_TIMED_CFG_GET;
        break;
    case TRANSMIT_TIMED_CFG_SET:
        cmd = GATEWAY_TIMED_CFG_SET;
        break;

    case TRANSMIT_IMMEDIATE_EFFECTIVE_GET:
        cmd = IMMEDIATE_EFFECTIVE_GET;
        break;
    case TRANSMIT_IMMEDIATE_EFFECTIVE_SET:
        cmd = IMMEDIATE_EFFECTIVE_SET;
        break;

    case TRANSMIT_MSH_CMD_EXEC:
        cmd = MSH_CMD_EXEC;
        break;

    case TRANSMIT_SYNC_CFG_GET:
        cmd = SYNC_CFG_GET;
        break;
    case TRANSMIT_SYNC_CFG_SET:
        cmd = SYNC_CFG_SET;
        break;

    case TRANSMIT_FACTORY_TEST_RESULT_GET:
        cmd = FACTORY_TEST_RESULT_GET;
        break;

    case TRANSMIT_USER_DATA_SEND:
        cmd = WIOTA_SEND_DATA;
        break;

    case TRANSMIT_TRANSPARENT_DATA_SEND:
        cmd = NET_SEND_TRANSPARENT_DATA;
        break;

    case TRANSMIT_ONLINE_DEVICE_GET:
        cmd = ONLINE_DEVICE_GET;
        break;

    case TRANSMIT_GATEWAY_TIME_GET:
        cmd = GATEWAY_TIME_GET;
        break;

    case TRANSMIT_SYNC_DYNAMIC_INFO_GET:
        cmd = SYNC_DYNAMICS_INFO_GET;
        break;

    default:
        break;
    }

    return cmd;
}

/**
 * @brief 将串口透传的用户下行数据，转成网络下行数据格式net_dl_userdata_t，发到manager线程，这样不用再加另外的case处理相同的数据流了
 *
 * @param data    串口透传的用户下行数据
 * @param len     串口透传的用户下行数据长度
 * @return char*  转换后的串口透传数据
 */
static char *downlink_transmit_handle_user_data(unsigned char *data, unsigned int len)
{
    int data_len = len - sizeof(transmit_user_data_t);
    transmit_user_data_t *user_data = (transmit_user_data_t *)data;
    net_dl_userdata_t *net_dl_data = RT_NULL;

    if (data_len <= 0)
    {
        return RT_NULL;
    }

    net_dl_data = rt_malloc(sizeof(net_dl_userdata_t));
    if (RT_NULL == net_dl_data)
    {
        return RT_NULL;
    }
    rt_memset(net_dl_data, 0, sizeof(net_dl_userdata_t));

    rt_memcpy(net_dl_data->fmt, user_data->fmt, sizeof(net_dl_data->fmt));
    net_dl_data->head.cmd = IOTE_USER_DATA;
    net_dl_data->order_business = user_data->ob;

    if (user_data->dev_id == 0 || user_data->dev_id == 0xFFFFFFFF)
    {
        // 没有设备id，表示发送广播数据
        net_dl_data->head.dest_num = 0;

        net_dl_data->broadcast_data = rt_malloc(data_len);
        if (RT_NULL == net_dl_data->broadcast_data)
        {
            rt_free(net_dl_data);
            return RT_NULL;
        }
        rt_memcpy(net_dl_data->broadcast_data, user_data->data, data_len);
        net_dl_data->broadcast_len = data_len;

        net_dl_data->unicast_data = RT_NULL;
        net_dl_data->unicast_len = 0;
    }
    else
    {
        // 有设备id，表示发送单播数据
        net_dl_data->head.dest_num = 1; // 目前只支持一个设备ID

        net_dl_data->head.dest_addr = rt_malloc(net_dl_data->head.dest_num * sizeof(unsigned int));
        if (RT_NULL == net_dl_data->head.dest_addr)
        {
            rt_free(net_dl_data);
            return RT_NULL;
        }
        net_dl_data->head.dest_addr[0] = user_data->dev_id;

        net_dl_data->unicast_data = rt_malloc(data_len);
        if (RT_NULL == net_dl_data->unicast_data)
        {
            rt_free(net_dl_data->head.dest_addr);
            rt_free(net_dl_data);
            return RT_NULL;
        }
        rt_memcpy(net_dl_data->unicast_data, user_data->data, data_len);
        net_dl_data->unicast_len = data_len;

        net_dl_data->broadcast_data = RT_NULL;
        net_dl_data->broadcast_len = 0;
    }

    return (char *)net_dl_data;
}

/**
 * @brief 将串口透传的数据，转成透传网络数据格式net_dl_traansparent_data_t，发到net_app线程，这样不用再在net_app中再加另外的处理函数了
 *
 * @param data    串口透传的数据
 * @param len     串口透传的数据长度
 * @return char*  转换后的串口透传数据
 */
static char *downlink_transmit_handle_transparent_data(unsigned char *data, unsigned int len)
{
    int data_len = len - sizeof(transmit_transparent_data_t);
    transmit_transparent_data_t *transparent_data = (transmit_transparent_data_t *)data;
    net_dl_transparent_data_t *net_dl_data = RT_NULL;

    if (data_len <= 0)
    {
        return RT_NULL;
    }

    net_dl_data = rt_malloc(sizeof(net_dl_transparent_data_t));
    if (RT_NULL == net_dl_data)
    {
        return RT_NULL;
    }
    rt_memset(net_dl_data, 0, sizeof(net_dl_transparent_data_t));

    rt_memcpy(net_dl_data->fmt, transparent_data->fmt, sizeof(net_dl_data->fmt));
    net_dl_data->cmd = PROT_TRANSPARENT_DATA;
    net_dl_data->src_addr = transparent_data->src_addr;
    net_dl_data->dest_addr = transparent_data->dest_addr;

    net_dl_data->transparent_data = rt_calloc(1, (data_len + 1));
    if (RT_NULL == net_dl_data->transparent_data)
    {
        rt_free(net_dl_data);
        return RT_NULL;
    }
    rt_memcpy(net_dl_data->transparent_data, transparent_data->data, data_len);
    net_dl_data->transparent_data_len = data_len;

    return (char *)net_dl_data;
}

static char *downlink_transmit_handle_gb15322_data(int cmd, s_gb_15322 *gb15322_data)
{
    unsigned int gb_data_len = gb15322_data->datalen;
    char *data_rx = RT_NULL;

    if (gb_data_len <= 0)
    {
        return RT_NULL;
    }

    switch (cmd)
    {
    case WIOTA_SEND_DATA:
        data_rx = downlink_transmit_handle_user_data(gb15322_data->data, gb_data_len);
        break;
    case NET_SEND_TRANSPARENT_DATA:
        data_rx = downlink_transmit_handle_transparent_data(gb15322_data->data, gb_data_len);
        break;

    default:
        data_rx = rt_malloc(gb_data_len);
        RT_ASSERT(data_rx);
        rt_memcpy(data_rx, gb15322_data->data, gb_data_len);
        break;
    }

    return data_rx;
}

int downlink_transmit_manager(unsigned int src_module, unsigned char *data, int len)
{
    int ret = -1;
    unsigned int cmd = -1;
    s_gb_15322 gb15322_data = {0};
    char *data_rx = RT_NULL;

    // test_data_print(__FUNCTION__, (char *)data, (len > 20) ? 20 : len);

    gb_15322_decode(data, len, &gb15322_data);

    cmd = transmit_cmd_to_wiota_cmd(gb15322_data.ctl);
    TRACE_D("dl_tran src_m %d, ctl %d to %d", src_module, gb15322_data.ctl, cmd);

    if (-1 == cmd)
    {
        return 1;
    }

    data_rx = downlink_transmit_handle_gb15322_data(cmd, &gb15322_data);

    if (NET_SEND_TRANSPARENT_DATA == cmd)
    {
        ret = module_queue_communication(net_app_get_queue(),
                                         src_module,
                                         NET_APP_MODULE,
                                         cmd,
                                         data_rx);
    }
    else
    {
        ret = module_queue_communication(get_gateway_manager_queue(),
                                         src_module,
                                         GATEWAY_MANAGER_MODULE,
                                         cmd,
                                         data_rx);
    }

    if (ret)
    {
        TRACE_E("send cmd 0x%X queue error %d", cmd, ret);
        if (RT_NULL != data_rx)
        {
            rt_free(data_rx);
            data_rx = RT_NULL;
        }
    }

    return ret;
}

static unsigned int wiota_cmd_to_transmit_cmd(unsigned int cmd, unsigned int *data_len)
{
    unsigned int trans_cmd = -1;

    switch (cmd)
    {
    case WIOAT_VERSION_GET:
        trans_cmd = TRANSMIT_WIOAT_VERSION_GET;
        *data_len = sizeof(wiota_version_t);
        break;

    case WIOTA_SYS_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_SYS_CFG_GET;
        *data_len = sizeof(wiota_sys_cfg_t);
        break;
    case WIOTA_SYS_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_SYS_CFG_SET;
        break;

    case WIOTA_ACT_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_ACT_CFG_GET;
        *data_len = sizeof(wiota_act_cfg_t);
        break;
    case WIOTA_ACT_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_ACT_CFG_SET;
        break;

    case WIOTA_FREQ_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_FREQ_CFG_GET;
        *data_len = sizeof(wiota_freq_cfg_t);
        break;
    case WIOTA_FREQ_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_FREQ_CFG_SET;
        break;

    case WIOTA_POWER_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_POWER_CFG_GET;
        *data_len = sizeof(wiota_power_cfg_t);
        break;
    case WIOTA_POWER_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_POWER_CFG_SET;
        break;

    case WIOTA_RATE_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_RATE_CFG_GET;
        *data_len = sizeof(wiota_rate_cfg_t);
        break;
    case WIOTA_RATE_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_RATE_CFG_SET;
        break;

    case WIOTA_PAGING_TX_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_PAGING_TX_CFG_GET;
        *data_len = sizeof(wiota_paging_tx_cfg_t);
        break;
    case WIOTA_PAGING_TX_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_PAGING_TX_CFG_SET;
        break;

    case WIOTA_SYNC_PAGING_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_SYNC_PAGING_CFG_GET;
        *data_len = sizeof(wiota_sync_paging_cfg_t);
        break;
    case WIOTA_SYNC_PAGING_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_SYNC_PAGING_CFG_SET;
        break;

    case WIOTA_TS_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_TS_CFG_GET;
        *data_len = sizeof(wiota_ts_cfg_t);
        break;
    case WIOTA_TS_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_TS_CFG_SET;
        break;

#ifdef WIOTA_SUBF_MODE_SUPPORT
    case WIOTA_SUBF_MODE_CFG_GET:
        trans_cmd = TRANSMIT_WIOTA_SUBF_MODE_CFG_GET;
        *data_len = sizeof(wiota_subf_mode_cfg_t);
        break;
    case WIOTA_SUBF_MODE_CFG_SET:
        trans_cmd = TRANSMIT_WIOTA_SUBF_MODE_CFG_SET;
        break;
#endif

    case SLOT_SEND_CFG_GET:
        trans_cmd = TRANSMIT_SLOT_SEND_CFG_GET;
        *data_len = sizeof(slot_send_cfg_t);
        break;
    case SLOT_SEND_CFG_SET:
        trans_cmd = TRANSMIT_SLOT_SEND_CFG_SET;
        *data_len = 7;
        break;

    case GATEWAY_BASE_CFG_GET:
        trans_cmd = TRANSMIT_GATEWAY_BASE_CFG_GET;
        *data_len = sizeof(gw_base_cfg_t);
        break;
    case GATEWAY_BASE_CFG_SET:
        trans_cmd = TRANSMIT_GATEWAY_BASE_CFG_SET;
        break;

    case ID_MANAGER_CFG_GET:
        trans_cmd = TRANSMIT_ID_MANAGER_CFG_GET;
        *data_len = sizeof(gw_id_manager_cfg_t);
        break;
    case ID_MANAGER_CFG_SET:
        trans_cmd = TRANSMIT_ID_MANAGER_CFG_SET;
        break;

    case AUTH_CFG_GET:
        trans_cmd = TRANSMIT_AUTH_CFG_GET;
        *data_len = sizeof(gw_auth_cfg_t);
        break;
    case AUTH_CFG_SET:
        trans_cmd = TRANSMIT_AUTH_CFG_SET;
        break;

    case NET_POLICY_CFG_GET:
        trans_cmd = TRANSMIT_NET_POLICY_CFG_GET;
        *data_len = sizeof(gw_net_policy_cfg_t);
        break;
    case NET_POLICY_CFG_SET:
        trans_cmd = TRANSMIT_NET_POLICY_CFG_SET;
        break;

    case NET_IF_CFG_GET:
        trans_cmd = TRANSMIT_NET_IF_CFG_GET;
        *data_len = sizeof(gw_net_if_cfg_t);
        break;
    case NET_IF_CFG_SET:
        trans_cmd = TRANSMIT_NET_IF_CFG_SET;
        break;

    case WIFI_CFG_GET:
        trans_cmd = TRANSMIT_WIFI_CFG_GET;
        *data_len = sizeof(gw_wifi_cfg_t);
        break;
    case WIFI_CFG_SET:
        trans_cmd = TRANSMIT_WIFI_CFG_SET;
        break;

    case CAT1_CFG_GET:
        trans_cmd = TRANSMIT_CAT1_CFG_GET;
        *data_len = sizeof(gw_cat1_cfg_t);
        break;
    case CAT1_CFG_SET:
        trans_cmd = TRANSMIT_CAT1_CFG_SET;
        break;

    case BT_CFG_GET:
        trans_cmd = TRANSMIT_BT_CFG_GET;
        *data_len = sizeof(gw_bt_cfg_t);
        break;

    case MQTT_SERVER_CFG_GET:
        trans_cmd = TRANSMIT_MQTT_SERVER_CFG_GET;
        *data_len = sizeof(gw_mqtt_server_cfg_t);
        break;
    case MQTT_SERVER_CFG_SET:
        trans_cmd = TRANSMIT_MQTT_SERVER_CFG_SET;
        break;

    case DATA_CFG_GET:
        trans_cmd = TRANSMIT_DATA_CFG_GET;
        *data_len = sizeof(gw_data_cfg_t);
        break;
    case DATA_CFG_SET:
        trans_cmd = TRANSMIT_DATA_CFG_SET;
        break;

    case WATCHDOG_CFG_GET:
        trans_cmd = TRANSMIT_WATCHDOG_CFG_GET;
        *data_len = sizeof(gw_wtd_cfg_t);
        break;
    case WATCHDOG_CFG_SET:
        trans_cmd = TRANSMIT_WATCHDOG_CFG_SET;
        break;

    case GATEWAY_FTP_LOG_CFG_GET:
        trans_cmd = TRANSMIT_FTP_LOG_CFG_GET;
        *data_len = sizeof(gw_ftp_log_cfg_t);
        break;
    case GATEWAY_FTP_LOG_CFG_SET:
        trans_cmd = TRANSMIT_FTP_LOG_CFG_SET;
        break;

    case LOG_SWITCH_CFG_GET:
        trans_cmd = TRANSMIT_LOG_SWITCH_CFG_GET;
        *data_len = sizeof(gw_log_switch_cfg_t);
        break;
    case LOG_SWITCH_CFG_SET:
        trans_cmd = TRANSMIT_LOG_SWITCH_CFG_SET;
        break;

    case UART_485_CFG_GET:
        trans_cmd = TRANSMIT_UART_485_CFG_GET;
        *data_len = sizeof(gw_uart_485_cfg_t);
        break;
    case UART_485_CFG_SET:
        trans_cmd = TRANSMIT_UART_485_CFG_SET;
        break;

    case GATEWAY_TIMED_CFG_GET:
        trans_cmd = TRANSMIT_TIMED_CFG_GET;
        *data_len = sizeof(gw_timed_cfg_t);
        break;
    case GATEWAY_TIMED_CFG_SET:
        trans_cmd = TRANSMIT_TIMED_CFG_SET;
        break;

    case RESET_FACTORY:
        trans_cmd = TRANSMIT_STATIC_DATA_INIT;
        break;

    case GATEWAY_REBOOT:
        trans_cmd = TRANSMIT_GATEWAY_REBOOT;
        break;

    case UBOOT_CFG_GET:
        trans_cmd = TRANSMIT_UBOOT_CFG_GET;
        *data_len = sizeof(uboot_cfg_t);
        break;
    case UBOOT_CFG_SET:
        trans_cmd = TRANSMIT_UBOOT_CFG_SET;
        break;

    case IMMEDIATE_EFFECTIVE_GET:
        trans_cmd = TRANSMIT_IMMEDIATE_EFFECTIVE_GET;
        *data_len = sizeof(int);
        break;
    case IMMEDIATE_EFFECTIVE_SET:
        trans_cmd = TRANSMIT_IMMEDIATE_EFFECTIVE_SET;
        break;

    case SYNC_CFG_GET:
        trans_cmd = TRANSMIT_SYNC_CFG_GET;
        *data_len = sizeof(sync_cfg_t);
        break;
    case SYNC_CFG_SET:
        trans_cmd = TRANSMIT_SYNC_CFG_SET;
        break;

    case MSH_CMD_EXEC:
        trans_cmd = TRANSMIT_MSH_CMD_EXEC;
        break;

    case FACTORY_TEST_RESULT_GET:
        trans_cmd = TRANSMIT_FACTORY_TEST_RESULT_GET;
        *data_len = sizeof(factory_test_t) * FACTORY_MODE;
        break;

    case NET_IOTE_STATE_UPDATE:
        trans_cmd = TRANSMIT_IOTE_STATE_RECV;
        // *data_len需要单独拿到
        break;

    case NET_IOTE_USER_DATA:
        trans_cmd = TRANSMIT_USER_DATA_RECV;
        // *data_len需要单独拿到
        break;

    case NET_SEND_TRANSPARENT_DATA:
        trans_cmd = TRANSMIT_TRANSPARENT_DATA_SEND;
        break;

    case NET_RECV_TRANSPARENT_DATA:
        trans_cmd = TRANSMIT_TRANSPARENT_DATA_RECV;
        break;

    case ONLINE_DEVICE_GET:
        trans_cmd = TRANSMIT_ONLINE_DEVICE_GET;
        break;

    case DEVICE_STATUS_GET:
        trans_cmd = TRANSMIT_DEVICE_STATUS_GET;
        break;

    case GATEWAY_TIME_GET:
        trans_cmd = TRANSMIT_GATEWAY_TIME_GET;
        *data_len = sizeof(int);
        break;

    case SYNC_DYNAMICS_INFO_GET:
        trans_cmd = TRANSMIT_SYNC_DYNAMIC_INFO_GET;
        *data_len = sizeof(sync_dynamics_info_t);
        break;

    default:
        break;
    }

    return trans_cmd;
}

static char *uplink_transmit_handle_data(int cmd, void *data, unsigned int *data_len, int *if_free_tx_data)
{
    char *data_tx = RT_NULL;
    unsigned int temp_data_len = *data_len;
    *if_free_tx_data = 1;

    switch (cmd)
    {
    case TRANSMIT_IOTE_STATE_RECV:
    {
        // dev_id + app_ps_iote_state_update_t
        mng_ul_iote_state_t *net_iote_state = (mng_ul_iote_state_t *)data;
        *data_len = sizeof(transmit_iote_state_t) + sizeof(app_ps_iote_state_update_t);

        transmit_iote_state_t *iote_state = (transmit_iote_state_t *)rt_malloc(*data_len);
        if (RT_NULL == iote_state)
        {
            return RT_NULL;
        }
        iote_state->dev_id = net_iote_state->head.src_addr;
        rt_memcpy(iote_state->data, &net_iote_state->state, sizeof(app_ps_iote_state_update_t));

        data_tx = (char *)iote_state;
        break;
    }

    case TRANSMIT_USER_DATA_RECV:
    {
        // dev_id + fmt_str + ob + data
        mng_ul_userdata_t *net_user_data = (mng_ul_userdata_t *)data;
        *data_len = sizeof(transmit_user_data_t) + net_user_data->data_len;

        transmit_user_data_t *user_data = (transmit_user_data_t *)rt_malloc(*data_len);
        if (RT_NULL == user_data)
        {
            return RT_NULL;
        }
        rt_memset(user_data, 0, *data_len);

        user_data->dev_id = net_user_data->head.src_addr;
        rt_memcpy(user_data->fmt, net_user_data->fmt, sizeof(user_data->fmt));
        rt_memcpy(user_data->data, net_user_data->data, net_user_data->data_len);

        data_tx = (char *)user_data;
        break;
    }

    case TRANSMIT_TRANSPARENT_DATA_RECV:
    {
        // dev_id + fmt_str + data
        net_dl_transparent_data_t *net_transparent_data = (net_dl_transparent_data_t *)data;
        *data_len = sizeof(transmit_transparent_data_t) + net_transparent_data->transparent_data_len;

        transmit_transparent_data_t *transparent_data = (transmit_transparent_data_t *)rt_malloc(*data_len);
        if (RT_NULL == transparent_data)
        {
            return RT_NULL;
        }
        rt_memset(transparent_data, 0, *data_len);

        transparent_data->src_addr = net_transparent_data->src_addr;
        transparent_data->dest_addr = net_transparent_data->dest_addr;
        rt_memcpy(transparent_data->fmt, net_transparent_data->fmt, sizeof(transparent_data->fmt));
        rt_memcpy(transparent_data->data, net_transparent_data->transparent_data, net_transparent_data->transparent_data_len);

        rt_free(net_transparent_data->transparent_data);
        net_transparent_data->transparent_data = RT_NULL; // 释放掉网络层传过来的data

        data_tx = (char *)transparent_data;
        break;
    }

    case TRANSMIT_ONLINE_DEVICE_GET:
    {
        online_device_list_t *online_device_list = (online_device_list_t *)data;
        *data_len = sizeof(online_device_list_t) + (sizeof(unsigned int) * online_device_list->online_number);
        data_tx = data;
        *if_free_tx_data = 0;
        break;
    }

    case TRANSMIT_DEVICE_STATUS_GET:
    {
        mng_ul_device_status_t *ul_device_status = (mng_ul_device_status_t *)data;
        *data_len = sizeof(transmit_device_status_t);

        transmit_device_status_t *device_status = (transmit_device_status_t *)rt_malloc(*data_len);
        if (RT_NULL == device_status)
        {
            return RT_NULL;
        }
        rt_memset(device_status, 0, *data_len);

        device_status->dev_id = ul_device_status->dev_id;
        device_status->status = ul_device_status->status;

        data_tx = (char *)device_status;
        break;
    }

    default:
        data_tx = data;
        *data_len = temp_data_len;
        *if_free_tx_data = 0;
        break;
    }

    return data_tx;
}

int uplink_transmit_manager(unsigned int addr, int dest_module, int cmd, void *data)
{
    char *encode_data = RT_NULL;
    int encode_len = 0;
    unsigned char trans_cmd = -1;
    unsigned int data_len = 1;
    char *data_tx = RT_NULL;
    int if_free_tx_data = 0;

    // wiota_test_command(__FUNCTION__, cmd);

    trans_cmd = wiota_cmd_to_transmit_cmd(cmd, &data_len);

    TRACE_D("ul_tran dst_m %d, ctl %d to %d", dest_module, cmd, trans_cmd);

    if (-1 == trans_cmd)
    {
        return 1;
    }

    data_tx = uplink_transmit_handle_data(trans_cmd, data, &data_len, &if_free_tx_data);
    if (data_tx == RT_NULL)
    {
        return 2;
    }
    if (gb_15322_response(addr,
                          trans_cmd,
                          data_tx,
                          data_len,
                          &encode_data,
                          &encode_len))
    {
        return 1;
    }

    if (if_free_tx_data) // 终端主动上行命令单独malloc了，需要单独free
    {
        rt_free(data_tx);
    }

    // rt_kprintf("encode_len %d\n", encode_len);
    // for (int i = 0; i < encode_len; i++)
    // {
    //     rt_kprintf("%x ", encode_data[i]);
    // }
    // rt_kprintf("\n");

    if ((RT_NULL != encode_data) && (encode_len > 0))
    {
        serial_write(dest_module, encode_data, encode_len);
    }

    if (RT_NULL != encode_data)
    {
        rt_free(encode_data);
        encode_data = RT_NULL;
    }

    return 0;
}